home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / nfsmount / nfsName.c < prev    next >
C/C++ Source or Header  |  1991-10-20  |  34KB  |  1,084 lines

  1. /*
  2.  * nfsName.c --
  3.  * 
  4.  *    Procedures that interface to a remote NFS filesystem.  The procedures
  5.  *    here are called via the Pfs/Pdev library in response to naming requests
  6.  *    from the Sprite kernel about files in an NFS filesystem.
  7.  *
  8.  * Copyright 1988 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/src/cmds/nfsmount/RCS/nfsName.c,v 1.18 91/09/24 11:47:50 mottsmth Exp $ SPRITE (Berkeley)";
  19. #endif not lint
  20.  
  21. #include "stdio.h"
  22.  
  23. #include "nfs.h"
  24. #include "sys/stat.h"
  25.  
  26. int nfsToSpriteFileType[] = {
  27.     FS_PSEUDO_DEV,        /* NFNON */
  28.     FS_FILE,            /* NFREG */
  29.     FS_DIRECTORY,        /* NFDIR */
  30.     FS_DEVICE,            /* NFBLK */
  31.     FS_DEVICE,            /* NFCHR */
  32.     FS_SYMBOLIC_LINK,        /* NFLNK */
  33. };
  34. int spriteToNfsModeType[] = {
  35.     S_IFREG,     /* FS_FILE */
  36.     S_IFDIR,    /* FS_DIRECTORY */
  37.     S_IFLNK,    /* FS_SYMBOLIC_LINK */
  38.     S_IFLNK,    /* FS_REMOTE_LINK */
  39.     S_IFCHR,    /* FS_DEVICE */
  40.     0,        /* FS_REMOTE_DEVICE - not used by Sprite */
  41.     0,        /* FS_LOCAL_PIPE - never seen by open */
  42.     S_IFIFO,    /* FS_NAMED_PIPE */
  43.     S_IFSOCK,    /* FS_PSEUDO_DEVICE */
  44.     S_IFLNK,    /* FS_PSEUDO_FS */
  45.     0,        /* FS_XTRA_FILE - used to test new Sprite types */
  46. };
  47.  
  48. /*
  49.  * Open file table.  A simple array of pointers to nfs_fh that
  50.  * is used to map between a Fs_FileID we give the Sprite kernel
  51.  * each time an NFS file is opened.  The minor field of the Sprite
  52.  * fileID is used as an index into this array of pointers to NFS handles.
  53.  */
  54. NfsOpenFile **nfsFileTable = (NfsOpenFile **)NULL;
  55. NfsOpenFile **nextFreeSlot = (NfsOpenFile **)NULL;
  56. int nfsFileTableSize = 0;
  57.  
  58. /*
  59.  * The following macro is used to map from a Sprite file ID to an NFS handle.
  60.  * This is used to interpret the prefixID passed to us on lookup operations.
  61.  * The Sprite kernel passes us a completly zero'd fileID for
  62.  * names that start at our root.  Otherwise it passes us the
  63.  * fileID we gave it when the process opened its current directory.
  64.  */
  65. #define PrefixIDToHandle(prefixID) \
  66.     ( (prefixID.type == TYPE_ROOT) ? (NfsOpenFile *)NULL : \
  67.     ((nfsFileTable == (NfsOpenFile **)NULL) ? (NfsOpenFile *)NULL : \
  68.         nfsFileTable[prefixID.minor] ) )
  69.  
  70. /*
  71.  * The set of callback procedures given to Pfs_Open.  These define the
  72.  * procedures called in response to pseudo-filesystem naming operations.
  73.  */
  74. Pfs_CallBacks nfsNameService= {
  75.     NfsOpen,            /* PFS_OPEN */
  76.     NfsGetAttrPath,        /* PFS_GET_ATTR */
  77.     NfsSetAttrPath,        /* PFS_SET_ATTR */
  78.     NfsMakeDevice,        /* PFS_MAKE_DEVICE */
  79.     NfsMakeDir,            /* PFS_MAKE_DIR */
  80.     NfsRemove,            /* PFS_REMOVE */
  81.     NfsRemoveDir,        /* PFS_REMOVE_DIR */
  82.     NfsRename,            /* PFS_RENAME */
  83.     NfsHardLink,        /* PFS_HARD_LINK */
  84.     NfsSymLink,            /* PFS_SYM_LINK */
  85.     NfsDomainInfo,         /* PFS_DOMAIN_INFO */
  86. };
  87.  
  88. void NfsSetupAuth();
  89.  
  90.  
  91. /*
  92.  *----------------------------------------------------------------------
  93.  *
  94.  * Nfs_InitClient --
  95.  *
  96.  *    Set up the CLIENT data structure needed to do SUN RPC to the
  97.  *    NFS server running on a particular host.
  98.  * 
  99.  * Results:
  100.  *    None.
  101.  *
  102.  * Side effects:
  103.  *    Calls clnt_create which sets up sockets and other related state.
  104.  *
  105.  *----------------------------------------------------------------------
  106.  */
  107. CLIENT *
  108. Nfs_InitClient(host)
  109.     char *host;
  110. {
  111.     register CLIENT *clnt;
  112.     VoidPtr voidArg;
  113.     VoidPtr voidRes;
  114.     int retryCnt = -1; /* infinite retries */
  115.  
  116.     clnt = clnt_create(host, NFS_PROGRAM, NFS_VERSION, "udp");
  117.     if (clnt == (CLIENT *)NULL) {
  118.     clnt_pcreateerror(host);
  119.     } else {
  120.     clnt->cl_auth = authunix_create_default();
  121.     if (!clnt_control(clnt, CLSET_RETRY_COUNT, &retryCnt)) {
  122.         clnt_perror(clnt, "clnt_control");
  123.     } else {
  124.         voidRes = nfsproc_null_2(&voidArg, clnt);
  125.         if (voidRes == (VoidPtr)NULL) {
  126.         clnt_perror(clnt, "nfsproc_null_2");
  127.         } else if (pdev_Trace) {
  128.         printf("Null RPC to NFS service at %s succeeded\n", host);
  129.         }
  130.     }
  131.     }
  132.     return(clnt);
  133. }
  134.  
  135. /*
  136.  *----------------------------------------------------------------------
  137.  *
  138.  * NfsProbe --
  139.  *
  140.  *    Called to test NFS access.  This dos a stat of the root of the
  141.  *    NFS system we have mounted.  The stat information is returned
  142.  *    so the pseudo-file-system server can properly establish the
  143.  *    user-visible fileID of the root.
  144.  * 
  145.  * Results:
  146.  *    1 if probe succeeded, 0 otherwise.
  147.  *
  148.  * Side effects:
  149.  *    Fills in the NFS attributes of the root directory.
  150.  *
  151.  *----------------------------------------------------------------------
  152.  */
  153.  
  154. int
  155. NfsProbe(nfsPtr, print, nfsAttrPtr)
  156.     NfsState *nfsPtr;        /* Top level state for NFS connection */
  157.     int print;            /* 1 to print out attributes */
  158.     attrstat *nfsAttrPtr;    /* NFS attributes of root */
  159. {
  160.  
  161.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_GETATTR, xdr_nfs_fh,
  162.         nfsPtr->mountHandle,
  163.         xdr_attrstat, nfsAttrPtr, nfsTimeout) != RPC_SUCCESS) {
  164.     clnt_perror(nfsPtr->nfsClnt, "NFSPROC_GETATTR");
  165.     return(0);
  166.     } else if (nfsAttrPtr->status != NFS_OK) {
  167.     printf("NfsProbe: Get attributes status %d\n", nfsAttrPtr->status);
  168.     return(0);
  169.     } else if (print) {
  170.     printf("Attributes of %s:%s\n", nfsPtr->host, nfsPtr->nfsName);
  171.     printf("\tFileID %x FS_ID %x\n",
  172.         nfsAttrPtr->attrstat_u.attributes.fileid,
  173.         nfsAttrPtr->attrstat_u.attributes.fsid);
  174.     printf("\tType %d mode 0%o links %d size %d\n",
  175.         nfsAttrPtr->attrstat_u.attributes.type,
  176.         nfsAttrPtr->attrstat_u.attributes.mode,
  177.         nfsAttrPtr->attrstat_u.attributes.nlink,
  178.         nfsAttrPtr->attrstat_u.attributes.size);
  179.     }
  180.     return(1);
  181. }
  182.  
  183. /*
  184.  *----------------------------------------------------------------------
  185.  *
  186.  * NfsOpen --
  187.  *
  188.  *    Called to open a file in the NFS system.  This does the open
  189.  *    with the NFS server and then opens a new pseudo-device connection
  190.  *    that will be used for all further operatiosn on the NFS file.
  191.  * 
  192.  * Results:
  193.  *    None.
  194.  *
  195.  * Side effects:
  196.  *    Calls clnt_create which sets up sockets and other related state.
  197.  *
  198.  *----------------------------------------------------------------------
  199.  */
  200. int
  201. NfsOpen(clientData, name, openArgsPtr, redirectInfoPtr)
  202.     ClientData clientData;        /* Ref. to NfsState */
  203.     char *name;                /* Pathname to open */
  204.     register Fs_OpenArgs *openArgsPtr;    /* Bundled arguments */
  205.     Fs_RedirectInfo *redirectInfoPtr;    /* Used when name leaves our domain */
  206. {
  207.     NfsState *nfsPtr = (NfsState *)clientData;
  208.     NfsOpenFile *cwdFilePtr;
  209.     Pdev_Stream *streamPtr;
  210.     diropres longDirResults;
  211.     diropokres *dirResultsPtr = &longDirResults.diropres_u.diropres;
  212.     createargs createArgs;
  213.     diropargs *wherePtr = &createArgs.where;
  214.     int status;
  215.     char component[NFS_MAXNAMLEN];
  216.     int created = 0;
  217.     int writeBehind = nfs_PdevWriteBehind;
  218.  
  219.     wherePtr->name = component;
  220.     cwdFilePtr = PrefixIDToHandle(openArgsPtr->prefixID);
  221.     NfsSetupAuth(nfsPtr, cwdFilePtr, &openArgsPtr->id);
  222.     status = NfsLookup(nfsPtr, cwdFilePtr, name, openArgsPtr->useFlags,
  223.                dirResultsPtr, &wherePtr, redirectInfoPtr);
  224.     if (status == NFSERR_NOENT && wherePtr != (diropargs *)NULL &&
  225.         (openArgsPtr->useFlags & FS_CREATE)) {
  226.     /*
  227.      * We need to create the file.  NfsLookup has set up createArgs.where
  228.      * to have the handle on the parent and the component to create.
  229.      */
  230.     register sattr *sattrPtr = &createArgs.attributes;
  231.  
  232.     sattrPtr->mode = openArgsPtr->permissions & 07777;
  233.     if (openArgsPtr->type >= 0 && openArgsPtr->type <= FS_XTRA_FILE) {
  234.         sattrPtr->mode |= spriteToNfsModeType[openArgsPtr->type];
  235.     } else {
  236.         printf("Open(\"%s\") bad type %d\n", name, openArgsPtr->type);
  237.         return(GEN_INVALID_ARG);
  238.     }
  239.     sattrPtr->uid = openArgsPtr->id.user;
  240.     sattrPtr->gid = -1;
  241.     sattrPtr->size = 0;
  242.     sattrPtr->atime.seconds = -1;
  243.     sattrPtr->atime.useconds = -1;
  244.     sattrPtr->mtime.seconds = -1;
  245.     sattrPtr->mtime.useconds = -1;
  246.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_CREATE, xdr_createargs,
  247.         &createArgs, xdr_diropres, &longDirResults, nfsTimeout)
  248.             != RPC_SUCCESS) {
  249.         clnt_perror(nfsPtr->nfsClnt, "NFSPROC_CREATE");
  250.         return(FAILURE);
  251.     }
  252.     status = longDirResults.status;
  253.     created = 1;
  254.     }
  255.     if (status != NFS_OK) {
  256.     status = NfsStatusMap(status);
  257.     } else {
  258.     register Fs_FileID *fileIDPtr;
  259.     register int full = 0;
  260.     /*
  261.      * We've got a good handle on the NFS file.  Time to do our own
  262.      * permission checking cause the NFS server is pretty lame.
  263.      */
  264.     status = CheckPermissions(&dirResultsPtr->attributes, created,
  265.           openArgsPtr->useFlags, &openArgsPtr->id, openArgsPtr->type);
  266.     if (status != SUCCESS) {
  267.         return(status);
  268.     }
  269.     /* 
  270.      * Save our file handle in an array indexed by part of the Fs_FileID
  271.      * we'll give to the Sprite kernel and to the pdev callback library.
  272.      * This will let us get back to the handle from prefixID's in open
  273.      * arguments, and from the client data passed to us from the callback
  274.      * library.
  275.      */
  276.     if (nfsFileTable == (NfsOpenFile **)NULL) {
  277.         /*
  278.          * Allocate and initialize the table.  It might grow later.
  279.          */
  280.         nfsFileTable = (NfsOpenFile **)malloc(64 * sizeof(NfsOpenFile *));
  281.         bzero((char *)nfsFileTable, 64 * sizeof(NfsOpenFile *));
  282.         nextFreeSlot = &nfsFileTable[0];
  283.         nfsFileTableSize = 64;
  284.     }
  285.     while (*nextFreeSlot != (NfsOpenFile *)NULL) {
  286.         nextFreeSlot++;
  287.         if (nextFreeSlot >= &nfsFileTable[nfsFileTableSize]) {
  288.         if (!full){
  289.             nextFreeSlot = &nfsFileTable[0];
  290.             full = 1;
  291.         } else {
  292.             /*
  293.              * Grow the table.
  294.              */
  295.             register NfsOpenFile **newTable =
  296.                 (NfsOpenFile **)malloc(nfsFileTableSize * 2 *
  297.                           sizeof(NfsOpenFile *));
  298.             bcopy((char *)nfsFileTable, (char *)newTable,
  299.                 nfsFileTableSize * sizeof(NfsOpenFile *));
  300.             bzero((char *)&newTable[nfsFileTableSize],
  301.                 nfsFileTableSize * sizeof(NfsOpenFile *));
  302.             free((char *)nfsFileTable);
  303.             nfsFileTable = newTable;
  304.             nextFreeSlot = &nfsFileTable[nfsFileTableSize];
  305.             nfsFileTableSize *= 2;
  306.          }
  307.          }
  308.      }
  309.      /*
  310.       * Save the NFS handle and the UNIX authentication of this user.
  311.       */
  312.      *nextFreeSlot = (NfsOpenFile *)malloc(sizeof(NfsOpenFile));
  313.      (*nextFreeSlot)->handlePtr = (nfs_fh *)malloc(sizeof(nfs_fh));
  314.      bcopy((char *)&dirResultsPtr->file,
  315.            (char *)(*nextFreeSlot)->handlePtr, NFS_FHSIZE);
  316.      {
  317.          register int numGroups;
  318.          numGroups = (openArgsPtr->id.numGroupIDs <= NGRPS) ?
  319.                  openArgsPtr->id.numGroupIDs : NGRPS ;
  320.          (*nextFreeSlot)->authPtr = authunix_create(myhostname,
  321.              openArgsPtr->id.user, openArgsPtr->id.group[0],
  322.              numGroups, openArgsPtr->id.group);
  323.     }
  324.      (*nextFreeSlot)->openFlags = openArgsPtr->useFlags;
  325.      /*
  326.       * Tell the Sprite kernel to set up a pseudo-device connection
  327.       * over which we'll see all future operations on the NFS file.
  328.       * The fileID we give here will come back to us if this open is
  329.       * for a chdir(); the fileID will be passed as the prefixID in
  330.       * the openArgs.  We set the type in order to differentiate
  331.       * it from the type of zero used for the fileID of our root.
  332.       */
  333.      fileIDPtr = (Fs_FileID *)malloc(sizeof(Fs_FileID));
  334.      fileIDPtr->minor = nextFreeSlot - nfsFileTable;
  335.      fileIDPtr->major = 0;
  336.      fileIDPtr->serverID = (int)nfsPtr;
  337.      switch(dirResultsPtr->attributes.type) {
  338.          case NFDIR:
  339.          fileIDPtr->type = TYPE_DIRECTORY;
  340.          break;
  341.          case NFLNK:
  342.          fileIDPtr->type = TYPE_SYMLINK;
  343.          break;
  344.          default:
  345.          fileIDPtr->type = TYPE_FILE;
  346.          writeBehind = 1;
  347.          break;
  348.      }
  349.      streamPtr = Pfs_OpenConnection(nfsPtr->pfsToken, fileIDPtr,
  350.              (16 * 1024) + 128,    /* request buffer size */
  351.              0, NULL,        /* no read buffer */
  352.              FS_READABLE | FS_WRITABLE, &nfsFileService);
  353.      /*
  354.       * Enable write-behind.  We'd like to let a writer overlap its writes.
  355.       * The request buffer is large enough for 2 8K block writes.  Using
  356.       * write-behind increases the write bandwidth from 9k/sec to 40k/sec.
  357.       */
  358.      if (streamPtr != (Pdev_Stream *)NULL) {
  359.          if (Fs_IOControl(streamPtr->streamID, IOC_PDEV_WRITE_BEHIND,
  360.                   sizeof(int), &writeBehind, 0, NULL) != 0) {
  361.          fprintf(stderr, "IOC_PDEV_WRITE_BEHIND failed\n");
  362.          }
  363.          streamPtr->clientData = (ClientData)fileIDPtr;
  364.      } else {
  365.          status = EINVAL;
  366.      }
  367.      }
  368.     return(status);
  369. }
  370.  
  371. /*
  372.  *----------------------------------------------------------------------
  373.  *
  374.  * NfsSetupAuth --
  375.  *
  376.  *    This procedure initializes the authentication information for
  377.  *    the NFS client structure.  It uses the AUTH * of the open
  378.  *    NFS file if possible.  For absolute pathnames, however, this
  379.  *    hasn't been setup yet so we do it here.
  380.  * 
  381.  * Results:
  382.  *    None.
  383.  *
  384.  * Side effects:
  385.  *    For absolute paths we create an AUTH structure that won't get free'd.
  386.  *   
  387.  *      True; it wasn't being freed, and at 500 bytes a pop it was
  388.  *      consuming major heap space. I added oldAuth to remember the pointer
  389.  *      and free it next time we come through here. JMS.
  390.  *      
  391.  *----------------------------------------------------------------------
  392.  */
  393. void
  394. NfsSetupAuth(nfsPtr, cwdFilePtr, idPtr)
  395.     NfsState *nfsPtr;
  396.     NfsOpenFile *cwdFilePtr;
  397.     Fs_UserIDs *idPtr;
  398. {
  399.     static AUTH *oldAuth = (AUTH *)NULL;
  400.  
  401.     if (oldAuth != (AUTH *)NULL) {
  402.     AUTH_DESTROY(oldAuth);
  403.     oldAuth = (AUTH *)NULL;
  404.     }
  405.     if (cwdFilePtr != (NfsOpenFile *)NULL) {
  406.     nfsPtr->nfsClnt->cl_auth = cwdFilePtr->authPtr;
  407.     } else {
  408.     if (idPtr->numGroupIDs > NGRPS) {
  409.         /*
  410.          * Patch so xdr_auth_unix doesn't fail.
  411.          */
  412.         idPtr->numGroupIDs = NGRPS;
  413.     }
  414.     oldAuth = nfsPtr->nfsClnt->cl_auth = authunix_create(myhostname,
  415.         idPtr->user, idPtr->group[0], idPtr->numGroupIDs, idPtr->group);
  416.     }
  417. }
  418.  
  419. /*
  420.  *----------------------------------------------------------------------
  421.  *
  422.  * CheckPermissions --
  423.  *
  424.  *    Client side permission checking so we can make an open fail
  425.  *    if the permissions are not sufficient.  The NFS server lets
  426.  *    any lookup request succeed if the client has permission over
  427.  *    the search path, and then does more permission checking at
  428.  *    each I/O.  Accordingly, we have to do a little more work at open time.
  429.  * 
  430.  * Results:
  431.  *    SUCCESS or an error code.
  432.  *
  433.  * Side effects:
  434.  *    None.
  435.  *
  436.  *----------------------------------------------------------------------
  437.  */
  438. int
  439.     CheckPermissions(nfsAttrPtr, created, useFlags, idPtr, wantType)
  440.     register fattr *nfsAttrPtr;
  441.     int created;
  442.     register int useFlags;
  443.     register Fs_UserIDs *idPtr;
  444.     register int wantType;
  445. {
  446.     register int thisType = nfsToSpriteFileType[(int)nfsAttrPtr->type];
  447.     register int index;
  448.     register int permBits;
  449.     register int *groupPtr;
  450.     register int status;
  451.  
  452.     /*
  453.      * Make sure the file type matches.  FS_FILE means any type, otherwise
  454.      * it should match exactly.  We have to patch 'thisType' of
  455.      * SYMBOLIC_LINK to REMOTE_LINK because of a Sprite kernel bug
  456.      * where it asks for REMOTE_LINKS instead of symbolic links
  457.      * when implementing the readlink() system call.
  458.      */
  459.     if (wantType == FS_REMOTE_LINK) {
  460.     wantType = FS_SYMBOLIC_LINK;
  461.     }
  462.     if ((wantType != FS_FILE) && (wantType != thisType)) {
  463.     if (wantType == FS_DIRECTORY) {
  464.         return(FS_NOT_DIRECTORY);
  465.     } else {
  466.         return(FS_WRONG_TYPE);
  467.     }
  468.     }
  469.     /*
  470.      * Dis-allow execution of directories...
  471.      */
  472.     if ((wantType == FS_FILE) && (useFlags & FS_EXECUTE) &&
  473.     (thisType != FS_FILE)) {
  474.     return(FS_WRONG_TYPE);
  475.     }
  476.  
  477.     /* Removed check which disallowed execution of file across NFS */
  478.     /* since the kernel can now do it (without setuid or setgid) JMS */
  479.  
  480.     if (idPtr->user == 0) {
  481.     /*
  482.      * For normal files, only check for execute permission.  This
  483.      * prevents root from being able to execute ordinary files by
  484.      * accident.  However, root has complete access to directories.
  485.      */
  486.     if (thisType == FS_DIRECTORY) {
  487.         return(SUCCESS);
  488.     }
  489.     useFlags &= FS_EXECUTE;
  490.     }
  491.     /*
  492.      * Check read/write/exec permissions against one of the owner bits,
  493.      * the group bits, or the world bits.  'permBits' is set to
  494.      * be the corresponding bits from the attributes and then
  495.      * shifted over so the comparisions are against the WORLD bits.
  496.      */
  497.     if (idPtr->user == nfsAttrPtr->uid) {
  498.     /*
  499.      * Because NFS is stateless it can't do permission checking right.
  500.      * A direct quote:
  501.      * "the server's permission checking algorithm should allow the owner
  502.      * of a file to access it regardless of the permission setting"
  503.      *
  504.      * Thus we don't enforce any permission checking on the owner here
  505.      * if the file has just been created.
  506.      * This lets programs like "update" and "cp -p" that preserve
  507.      * permissions copy a read-only file.
  508.      */
  509.     if (!created) {
  510.         permBits = (nfsAttrPtr->mode >> 6) & 07;
  511.     } else {
  512.         permBits = 07;
  513.     }
  514.     } else {
  515.     for (index = idPtr->numGroupIDs, groupPtr = idPtr->group;
  516.          index > 0;
  517.          index--, groupPtr++) {
  518.         if (*groupPtr == nfsAttrPtr->gid) {
  519.         permBits = (nfsAttrPtr->mode >> 3) & 07;
  520.         goto havePermBits;
  521.         }
  522.     }
  523.     permBits = nfsAttrPtr->mode & 07;
  524.     }
  525. havePermBits:
  526.     if (((useFlags & FS_READ) && ((permBits & FS_WORLD_READ) == 0)) ||
  527.     ((useFlags & FS_WRITE) && ((permBits & FS_WORLD_WRITE) == 0)) ||
  528.     ((useFlags & FS_EXECUTE) && ((permBits & FS_WORLD_EXEC) == 0))) {
  529.     /*
  530.      * The file's permission don't include what is needed.
  531.      */
  532.     status = FS_NO_ACCESS;
  533.     } else {
  534.     status = SUCCESS;
  535.     }
  536.     return(status);
  537. }
  538.  
  539. /*
  540.  *----------------------------------------------------------------------
  541.  *
  542.  * NfsGetAttrPath --
  543.  *
  544.  *    Called to stat a file in the NFS system.
  545.  * 
  546.  * Results:
  547.  *    None.
  548.  *
  549.  * Side effects:
  550.  *    None.
  551.  *
  552.  *----------------------------------------------------------------------
  553.  */
  554. int
  555. NfsGetAttrPath(clientData, name, openArgsPtr, spriteAttrPtr, redirectInfoPtr)
  556.     ClientData clientData;            /* Ref. to NfsState */
  557.     char *name;                /* Pathname to open */
  558.     Fs_OpenArgs *openArgsPtr;        /* Bundled arguments */
  559.     Fs_Attributes *spriteAttrPtr;    /* Return - attributes of the file */
  560.     Fs_RedirectInfo *redirectInfoPtr;    /* Used when name leaves our domain */
  561. {
  562.     NfsState *nfsPtr = (NfsState *)clientData;
  563.     diropokres dirResults;
  564.     fattr *nfsAttrPtr = &dirResults.attributes;
  565.     NfsOpenFile *cwdFilePtr;
  566.     int status;
  567.  
  568.     cwdFilePtr = PrefixIDToHandle(openArgsPtr->prefixID);
  569.     status = NfsLookup(nfsPtr, cwdFilePtr, name, openArgsPtr->useFlags,
  570.             &dirResults, (diropargs *)NULL, redirectInfoPtr);
  571.  
  572.     if (status != NFS_OK) {
  573.     return(NfsStatusMap(status));
  574.     }
  575.     NfsToSpriteAttr(nfsAttrPtr, spriteAttrPtr);
  576.     return(0);
  577. }
  578.  
  579. /*
  580.  *----------------------------------------------------------------------
  581.  *
  582.  * NfsSetAttrPath --
  583.  *
  584.  *    Called to change attributes of a file in the NFS system.
  585.  * 
  586.  * Results:
  587.  *    None.
  588.  *
  589.  * Side effects:
  590.  *    None.
  591.  *
  592.  *----------------------------------------------------------------------
  593.  */
  594. int
  595. NfsSetAttrPath(clientData, name, openArgsPtr, flags, attrPtr, redirectInfoPtr)
  596.     ClientData clientData;        /* Ref. to NfsState */
  597.     char *name;            /* Pathname to open */
  598.     Fs_OpenArgs *openArgsPtr;    /* Bundled arguments */
  599.     int flags;            /* Specify which attributes to set */
  600.     Fs_Attributes *attrPtr;    /* New attributes of the file */
  601.     Fs_RedirectInfo *redirectInfoPtr;    /* Used when name leaves our domain */
  602. {
  603.     NfsState *nfsPtr = (NfsState *)clientData;
  604.     diropokres dirResults;
  605.     sattrargs sattrArgs;
  606.     attrstat attrStat;
  607.     NfsOpenFile *cwdFilePtr;
  608.     int status;
  609.  
  610.     cwdFilePtr = PrefixIDToHandle(openArgsPtr->prefixID);
  611.     status = NfsLookup(nfsPtr, cwdFilePtr, name, openArgsPtr->useFlags,
  612.             &dirResults, (diropargs **)NULL, redirectInfoPtr);
  613.  
  614.     if (status != NFS_OK) {
  615.     return(NfsStatusMap(status));
  616.     }
  617.     bcopy((char *)&dirResults.file, (char *)&sattrArgs.file, sizeof(nfs_fh));
  618.     SpriteToNfsAttr(flags, attrPtr, &sattrArgs.attributes);
  619.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_SETATTR, xdr_sattrargs, &sattrArgs,
  620.         xdr_attrstat, &attrStat, nfsTimeout) != RPC_SUCCESS) {
  621.     clnt_perror(nfsPtr->nfsClnt, "NFSPROC_SETATTR");
  622.     return(FAILURE);
  623.     } else {
  624.     return(NfsStatusMap((int)attrStat.status));
  625.     }
  626. }
  627.  
  628. /*
  629.  *----------------------------------------------------------------------
  630.  *
  631.  * NfsMakeDevice --
  632.  *
  633.  *    Called to create a special file (device) in the NFS system.
  634.  *    This isn't supported by the NFS protocol.
  635.  * 
  636.  * Results:
  637.  *    None.
  638.  *
  639.  * Side effects:
  640.  *    None.
  641.  *
  642.  *----------------------------------------------------------------------
  643.  */
  644. int
  645. NfsMakeDevice(clientData, name, makeDevArgsPtr, redirectInfoPtr)
  646.     ClientData clientData;            /* Ref. to NfsState */
  647.     char *name;                /* Pathname to open */
  648.     Fs_MakeDeviceArgs *makeDevArgsPtr;    /* Bundled arguments */
  649.     Fs_RedirectInfo *redirectInfoPtr;    /* Used when name leaves our domain */
  650. {
  651.     return(FS_NO_ACCESS);
  652. }
  653.  
  654. /*
  655.  *----------------------------------------------------------------------
  656.  *
  657.  * NfsMakeDir --
  658.  *
  659.  *    Called to make a directory in the NFS system.
  660.  * 
  661.  * Results:
  662.  *    None.
  663.  *
  664.  * Side effects:
  665.  *    None.
  666.  *
  667.  *----------------------------------------------------------------------
  668.  */
  669. int
  670. NfsMakeDir(clientData, name, openArgsPtr, redirectInfoPtr)
  671.     ClientData clientData;        /* Ref. to NfsState */
  672.     char *name;            /* Pathname to open */
  673.     Fs_OpenArgs *openArgsPtr;    /* Bundled arguments */
  674.     Fs_RedirectInfo *redirectInfoPtr;    /* Used when name leaves our domain */
  675. {
  676.     NfsOpenFile *cwdFilePtr;
  677.     NfsState *nfsPtr = (NfsState *)clientData;
  678.     diropres longDirResults;
  679.     diropokres *dirResultsPtr = &longDirResults.diropres_u.diropres;
  680.     createargs createArgs;
  681.     diropargs *wherePtr = &createArgs.where;
  682.     register sattr *sattrPtr = &createArgs.attributes;
  683.     int status;
  684.     char component[NFS_MAXNAMLEN];
  685.  
  686.     wherePtr->name = component;
  687.     cwdFilePtr = PrefixIDToHandle(openArgsPtr->prefixID);
  688.     status = NfsLookup(nfsPtr, cwdFilePtr, name, openArgsPtr->useFlags,
  689.                dirResultsPtr, &wherePtr, redirectInfoPtr);
  690.     if (status == NFS_OK) {
  691.     return(EEXIST);
  692.     } else if (status == NFSERR_NOENT) {
  693.     sattrPtr->mode = openArgsPtr->permissions & 07777 | S_IFDIR;
  694.     sattrPtr->uid = openArgsPtr->id.user;
  695.     sattrPtr->gid = -1;
  696.     sattrPtr->size = 0;
  697.     sattrPtr->atime.seconds = -1;
  698.     sattrPtr->atime.useconds = -1;
  699.     sattrPtr->mtime.seconds = -1;
  700.     sattrPtr->mtime.useconds = -1;
  701.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_MKDIR, xdr_createargs,
  702.         &createArgs, xdr_diropres, &longDirResults, nfsTimeout)
  703.             != RPC_SUCCESS) {
  704.         clnt_perror(nfsPtr->nfsClnt, "NFSPROC_MKDIR");
  705.         return(FAILURE);
  706.     }
  707.     status = longDirResults.status;
  708.     }
  709.     return(NfsStatusMap(status));
  710. }
  711.  
  712. /*
  713.  *----------------------------------------------------------------------
  714.  *
  715.  * NfsRemove --
  716.  *
  717.  *    Called to remove a file from the NFS system.
  718.  * 
  719.  * Results:
  720.  *    None.
  721.  *
  722.  * Side effects:
  723.  *    None.
  724.  *
  725.  *----------------------------------------------------------------------
  726.  */
  727. int
  728. NfsRemove(clientData, name, lookupArgsPtr, redirectInfoPtr)
  729.     ClientData clientData;            /* Ref. to NfsState */
  730.     char *name;                /* Pathname to open */
  731.     Fs_LookupArgs *lookupArgsPtr;    /* Bundled arguments */
  732.     Fs_RedirectInfo *redirectInfoPtr;    /* Used when name leaves our domain */
  733. {
  734.     NfsOpenFile *cwdFilePtr;
  735.     NfsState *nfsPtr = (NfsState *)clientData;
  736.     diropokres dirResults;
  737.     diropargs dirOpArgs;
  738.     diropargs *wherePtr = &dirOpArgs;
  739.     nfsstat nfsStatus;
  740.     int status;
  741.     char component[NFS_MAXNAMLEN];
  742.  
  743.     wherePtr->name = component;
  744.     cwdFilePtr = PrefixIDToHandle(lookupArgsPtr->prefixID);
  745.     status = NfsLookup(nfsPtr, cwdFilePtr, name, lookupArgsPtr->useFlags,
  746.                &dirResults, &wherePtr, redirectInfoPtr);
  747.     if (status == NFS_OK) {
  748.     if (dirResults.attributes.type == NFDIR) {
  749.         return(FS_WRONG_TYPE);
  750.     }
  751.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_REMOVE, xdr_diropargs,
  752.         wherePtr, xdr_nfsstat, &nfsStatus, nfsTimeout)
  753.             != RPC_SUCCESS) {
  754.         clnt_perror(nfsPtr->nfsClnt, "NFSPROC_REMOVE");
  755.         return(FAILURE);
  756.     }
  757.     status = (int)nfsStatus;
  758.     }
  759.     return(NfsStatusMap(status));
  760. }
  761.  
  762. /*
  763.  *----------------------------------------------------------------------
  764.  *
  765.  * NfsRemoveDir --
  766.  *
  767.  *    Called to remove a directory from the NFS system.
  768.  * 
  769.  * Results:
  770.  *    None.
  771.  *
  772.  * Side effects:
  773.  *    None.
  774.  *
  775.  *----------------------------------------------------------------------
  776.  */
  777. int
  778. NfsRemoveDir(clientData, name, lookupArgsPtr, redirectInfoPtr)
  779.     ClientData clientData;            /* Ref. to NfsState */
  780.     char *name;                /* Pathname to open */
  781.     Fs_LookupArgs *lookupArgsPtr;    /* Bundled arguments */
  782.     Fs_RedirectInfo *redirectInfoPtr;    /* Used when name leaves our domain */
  783. {
  784.     NfsOpenFile *cwdFilePtr;
  785.     NfsState *nfsPtr = (NfsState *)clientData;
  786.     diropokres dirResults;
  787.     diropargs dirOpArgs;
  788.     diropargs *wherePtr = &dirOpArgs;
  789.     nfsstat nfsStatus;
  790.     int status;
  791.     char component[NFS_MAXNAMLEN];
  792.  
  793.     wherePtr->name = component;
  794.     cwdFilePtr = PrefixIDToHandle(lookupArgsPtr->prefixID);
  795.     status = NfsLookup(nfsPtr, cwdFilePtr, name, lookupArgsPtr->useFlags,
  796.                &dirResults, &wherePtr, redirectInfoPtr);
  797.     if (status == NFS_OK) {
  798.     if (dirResults.attributes.type != NFDIR) {
  799.         return(FS_NOT_DIRECTORY);
  800.     }
  801.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_RMDIR, xdr_diropargs,
  802.         wherePtr, xdr_nfsstat, &nfsStatus, nfsTimeout)
  803.             != RPC_SUCCESS) {
  804.         clnt_perror(nfsPtr->nfsClnt, "NFSPROC_RMDIR");
  805.         return(FAILURE);
  806.     }
  807.     status = (int)nfsStatus;
  808.     }
  809.     return(NfsStatusMap(status));
  810. }
  811.  
  812. /*
  813.  *----------------------------------------------------------------------
  814.  *
  815.  * NfsRename --
  816.  *
  817.  *    Called to rename a file in the NFS system.
  818.  * 
  819.  * Results:
  820.  *    None.
  821.  *
  822.  * Side effects:
  823.  *    None.
  824.  *
  825.  *----------------------------------------------------------------------
  826.  */
  827. int
  828. NfsRename(clientData, srcName, dstName, twoNameArgsPtr, redirect2InfoPtr)
  829.     ClientData clientData;            /* Ref. to NfsState */
  830.     char *srcName;            /* Original name */
  831.     char *dstName;            /* New name */
  832.     Fs_2PathParams *twoNameArgsPtr;    /* Lookup args plus prefixID2 */
  833.     Fs_2PathRedirectInfo *redirect2InfoPtr;/* Used when name leaves our domain */
  834. {
  835.     NfsOpenFile *cwdFilePtr;
  836.     NfsState *nfsPtr = (NfsState *)clientData;
  837.     diropokres dirResults;
  838.     renameargs rename;
  839.     diropargs *fromPtr = &rename.from;
  840.     diropargs *toPtr = &rename.to;
  841.     nfsstat nfsStatus;
  842.     int status;
  843.     char component[NFS_MAXNAMLEN];
  844.     char component2[NFS_MAXNAMLEN];
  845.     Fs_RedirectInfo redirectInfo;
  846.  
  847.     fromPtr->name = component;
  848.     cwdFilePtr = PrefixIDToHandle(twoNameArgsPtr->lookup.prefixID);
  849.     status = NfsLookup(nfsPtr, cwdFilePtr, srcName,
  850.         twoNameArgsPtr->lookup.useFlags,
  851.             &dirResults, &fromPtr, &redirectInfo);
  852.     if (status == EREMOTE) {
  853.     redirect2InfoPtr->name1ErrorP = 1;
  854.     redirect2InfoPtr->prefixLength = redirectInfo.prefixLength;
  855.     strcpy(redirect2InfoPtr->fileName, redirectInfo.fileName);
  856.     return(EREMOTE);
  857.     } else if (status == NFS_OK) {
  858.     if (twoNameArgsPtr->prefixID2.type == -1) {
  859.         redirect2InfoPtr->name1ErrorP = 0;
  860.         redirect2InfoPtr->prefixLength = 0;
  861.         redirect2InfoPtr->fileName[0] = '\0';
  862.         return(FS_CROSS_DOMAIN_OPERATION);
  863.     }
  864.     toPtr->name = component2;
  865.     cwdFilePtr = PrefixIDToHandle(twoNameArgsPtr->prefixID2);
  866.     status = NfsLookup(nfsPtr, cwdFilePtr, dstName,
  867.             twoNameArgsPtr->lookup.useFlags,
  868.             &dirResults, &toPtr, &redirectInfo);
  869.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_RENAME, xdr_renameargs,
  870.         &rename, xdr_nfsstat, &nfsStatus, nfsTimeout)
  871.             != RPC_SUCCESS) {
  872.         clnt_perror(nfsPtr->nfsClnt, "NFSPROC_RENAME");
  873.         return(FAILURE);
  874.     }
  875.     status = (int)nfsStatus;
  876.     }
  877.     return(NfsStatusMap(status));
  878. }
  879.  
  880. /*
  881.  *----------------------------------------------------------------------
  882.  *
  883.  * NfsHardLink --
  884.  *
  885.  *    Make a hard link between two files in the NFS system.
  886.  * 
  887.  * Results:
  888.  *    None.
  889.  *
  890.  * Side effects:
  891.  *    None.
  892.  *
  893.  *----------------------------------------------------------------------
  894.  */
  895. int
  896. NfsHardLink(clientData, srcName, dstName, twoNameArgsPtr, redirect2InfoPtr)
  897.     ClientData clientData;            /* Ref. to NfsState */
  898.     char *srcName;            /* Original name */
  899.     char *dstName;            /* New name */
  900.     Fs_2PathParams *twoNameArgsPtr;    /* Lookup args plus prefixID2 */
  901.     Fs_2PathRedirectInfo *redirect2InfoPtr;/* Used when name leaves our domain */
  902. {
  903.     NfsOpenFile *cwdFilePtr;
  904.     NfsState *nfsPtr = (NfsState *)clientData;
  905.     diropokres dirResults;
  906.     linkargs link;
  907.     diropargs *toPtr = &link.to;
  908.     nfsstat nfsStatus;
  909.     int status;
  910.     char component[NFS_MAXNAMLEN];
  911.     Fs_RedirectInfo redirectInfo;
  912.  
  913.     cwdFilePtr = PrefixIDToHandle(twoNameArgsPtr->lookup.prefixID);
  914.     status = NfsLookup(nfsPtr, cwdFilePtr, srcName,
  915.         twoNameArgsPtr->lookup.useFlags,
  916.             &dirResults, (diropargs **)NULL, &redirectInfo);
  917.     if (status == EREMOTE) {
  918.     redirect2InfoPtr->name1ErrorP = 1;
  919.     redirect2InfoPtr->prefixLength = redirectInfo.prefixLength;
  920.     strcpy(redirect2InfoPtr->fileName, redirectInfo.fileName);
  921.     return(EREMOTE);
  922.     } else if (status == NFS_OK) {
  923.     if (twoNameArgsPtr->prefixID2.type == -1) {
  924.         redirect2InfoPtr->name1ErrorP = 0;
  925.         redirect2InfoPtr->prefixLength = 0;
  926.         redirect2InfoPtr->fileName[0] = '\0';
  927.         return(FS_CROSS_DOMAIN_OPERATION);
  928.     }
  929.     bcopy((char *)&dirResults.file, (char *)&link.from, sizeof(nfs_fh));
  930.     toPtr->name = component;
  931.     cwdFilePtr = PrefixIDToHandle(twoNameArgsPtr->prefixID2);
  932.     status = NfsLookup(nfsPtr, cwdFilePtr, dstName,
  933.             twoNameArgsPtr->lookup.useFlags,
  934.             &dirResults, &toPtr, &redirectInfo);
  935.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_LINK, xdr_linkargs,
  936.         &link, xdr_nfsstat, &nfsStatus, nfsTimeout)
  937.             != RPC_SUCCESS) {
  938.         clnt_perror(nfsPtr->nfsClnt, "NFSPROC_LINK");
  939.         return(FAILURE);
  940.     }
  941.     status = (int)nfsStatus;
  942.     }
  943.     return(NfsStatusMap(status));
  944. }
  945.  
  946.  
  947. /*
  948.  *----------------------------------------------------------------------
  949.  *
  950.  * NfsSymLink --
  951.  *
  952.  *    Called to make a symbolic link in the NFS system.
  953.  * 
  954.  * Results:
  955.  *    None.
  956.  *
  957.  * Side effects:
  958.  *    None.
  959.  *
  960.  *----------------------------------------------------------------------
  961.  */
  962. int
  963. NfsSymLink(clientData, linkName, value, openArgsPtr, redirectInfoPtr)
  964.     ClientData clientData;        /* Ref. to NfsState */
  965.     char *linkName;            /* Original name */
  966.     char *value;            /* New name */
  967.     Fs_OpenArgs *openArgsPtr;        /* Open arguments */
  968.     Fs_RedirectInfo *redirectInfoPtr;    /* Used when name leaves our domain */
  969. {
  970.     NfsOpenFile *cwdFilePtr;
  971.     NfsState *nfsPtr = (NfsState *)clientData;
  972.     diropokres dirResults;
  973.     symlinkargs symLinkArgs;
  974.     diropargs *wherePtr = &symLinkArgs.from;
  975.     register sattr *sattrPtr = &symLinkArgs.attributes;
  976.     nfsstat nfsStatus;
  977.     int status;
  978.     char component[NFS_MAXNAMLEN];
  979.  
  980.     symLinkArgs.to = value;
  981.     wherePtr->name = component;
  982.     cwdFilePtr = PrefixIDToHandle(openArgsPtr->prefixID);
  983.     status = NfsLookup(nfsPtr, cwdFilePtr, linkName,
  984.         openArgsPtr->useFlags,
  985.             &dirResults, &wherePtr, redirectInfoPtr);
  986.     if (status == NFS_OK) {
  987.     return(EEXIST);
  988.     } else if (status == NFSERR_NOENT) {
  989.     sattrPtr->mode = openArgsPtr->permissions & 07777 | S_IFLNK;
  990.     sattrPtr->uid = openArgsPtr->id.user;
  991.     sattrPtr->gid = -1;
  992.     sattrPtr->size = strlen(value);
  993.     sattrPtr->atime.seconds = -1;
  994.     sattrPtr->atime.useconds = -1;
  995.     sattrPtr->mtime.seconds = -1;
  996.     sattrPtr->mtime.useconds = -1;
  997.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_SYMLINK, xdr_symlinkargs,
  998.         &symLinkArgs, xdr_nfsstat, &nfsStatus, nfsTimeout)
  999.             != RPC_SUCCESS) {
  1000.         clnt_perror(nfsPtr->nfsClnt, "NFSPROC_MKDIR");
  1001.         return(FAILURE);
  1002.     }
  1003.     status = (int)nfsStatus;
  1004.     }
  1005.     return(status);
  1006. }
  1007.  
  1008.  
  1009. /*
  1010.  *----------------------------------------------------------------------
  1011.  *
  1012.  * NfsDomainInfo --
  1013.  *
  1014.  *    Called to find out about an NFS file system.
  1015.  * 
  1016.  * Results:
  1017.  *    The number of blocks and the number of free blocks in the file system.
  1018.  *
  1019.  * Side effects:
  1020.  *    None.
  1021.  *
  1022.  *----------------------------------------------------------------------
  1023.  */
  1024. /*ARGSUSED*/
  1025. int
  1026. NfsDomainInfo(clientData, fileIDPtr, domainInfoPtr)
  1027.     ClientData clientData;        /* Ref. to NfsState */
  1028.     Fs_FileID *fileIDPtr;        /* Handle on top-level directory */
  1029.     Fs_DomainInfo *domainInfoPtr;    /* Return information */
  1030. {
  1031.     NfsState *nfsPtr = (NfsState *)clientData;
  1032.     statfsres fsStat;
  1033.  
  1034.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_STATFS, xdr_nfs_fh,
  1035.         nfsPtr->mountHandle, xdr_statfsres, &fsStat, nfsTimeout)
  1036.             != RPC_SUCCESS) {
  1037.     clnt_perror(nfsPtr->nfsClnt, "NFSPROC_STATFS");
  1038.     return(FAILURE);
  1039.     } else if (fsStat.status != NFS_OK) {
  1040.     return(fsStat.status);
  1041.     } else {
  1042.     domainInfoPtr->maxKbytes = fsStat.statfsres_u.reply.blocks *
  1043.                    fsStat.statfsres_u.reply.bsize / 1024;
  1044.     domainInfoPtr->freeKbytes = fsStat.statfsres_u.reply.bfree *
  1045.                    fsStat.statfsres_u.reply.bsize / 1024;
  1046.     domainInfoPtr->maxFileDesc = -1;
  1047.     domainInfoPtr->freeFileDesc = -1;
  1048.     domainInfoPtr->blockSize = fsStat.statfsres_u.reply.bsize;
  1049.     domainInfoPtr->optSize = fsStat.statfsres_u.reply.tsize;
  1050.     return(SUCCESS);
  1051.     }
  1052. }
  1053.  
  1054. /*
  1055.  *----------------------------------------------------------------------
  1056.  *
  1057.  * NfsHandlePrint --
  1058.  *
  1059.  *    Print out an NFS handle.
  1060.  * 
  1061.  * Results:
  1062.  *    None.
  1063.  *
  1064.  * Side effects:
  1065.  *    None.
  1066.  *
  1067.  *----------------------------------------------------------------------
  1068.  */
  1069. int
  1070. NfsHandlePrint(handlePtr)
  1071.     nfs_fh *handlePtr;
  1072. {
  1073.     register int i;
  1074.     register int *intPtr = (int *)handlePtr;
  1075.  
  1076.     printf("<");
  1077.     for (i=0 ; i<FHSIZE ; i += sizeof(int)) {
  1078.     printf("%x,", *intPtr);
  1079.     intPtr++;
  1080.     }
  1081.     printf(">");
  1082. }
  1083.  
  1084.